﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.ComponentModel;
using System.Threading;

namespace PWAsker
{
    public class Executable : INotifyPropertyChanged
    {
        //serialized objects + setter/getter
        private String _szCommand;
        public String ExecCommand
        {
            get { return _szCommand; }
            set { _szCommand = value; OnPropertyChanged("ExecCommand"); }
        }

        //if true, wait until command exits sucessfully before issuing next command. If _WaitSecs is not 0, wait max _WaitSecs seconds
        private Boolean _WaitForCommand;
        public Boolean WaitForCommand
        {
            get { return _WaitForCommand; }
            set { _WaitForCommand = value; OnPropertyChanged("WaitForCommand"); }
        }

        //if not 0, wait x seonds after issuing this command until execution of next command. If _WaitForCommand is set, abort wating if current command exits
        private int _WaitSecs;
        public int WaitSecs
        {
            get { return _WaitSecs; }
            set { _WaitSecs = value; OnPropertyChanged("WaitSecs"); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        
        //default constuctor
        public Executable()
        {
            _szCommand = String.Empty;
            Debug.WriteLine("New empty executable-object generated.");
        }

        //parametrized constructor
        public Executable(String szCommand, Boolean WaitForCommand, int WaitSecs)
        {
            this._szCommand = szCommand;
            this._WaitForCommand = WaitForCommand;
            this._WaitSecs = WaitSecs;
            Debug.WriteLine("New executable-object generated. Dump: " + _szCommand + " - " + _WaitForCommand + " - " + _WaitSecs);
        }

        //PropertyChanged event-handler
        protected void OnPropertyChanged(string info)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if( handler != null)
            {
                handler(this, new PropertyChangedEventArgs(info));
            }
        }

        //Overriding string-representation
        public override string ToString()
        {
            return _szCommand;
        }

        //compares current executable to another
        public Boolean compare(Executable exec)
        {
            return compare(this, exec);
        }

        //compares two executables.
        public static Boolean compare(Executable exec1, Executable exec2)
        {

            if (exec1._szCommand != exec2._szCommand)
            {
                return false;
            }

            if (exec1._WaitForCommand != exec2._WaitForCommand)
            {
                return false;
            }

            if (exec1._WaitSecs != exec2._WaitSecs)
            {
                return false;
            }
               
            return true;
        }

        //executes the executable
        public void execute(String szPass, String szRegex)
        {
            String szExecString = replaceRegex(_szCommand, szPass, szRegex);
            Debug.WriteLine("Replaced " + _szCommand + " with " + szExecString + " for execution");
            String szFilename = splitFilename(szExecString);
            String szArgs = szExecString.Substring(szFilename.Length);

            Debug.WriteLine("Executing file: " + szFilename + " with argument " + szArgs);
            System.Diagnostics.Process cmd = new System.Diagnostics.Process();
            cmd.EnableRaisingEvents = false;
            cmd.StartInfo.FileName = szFilename;
            cmd.StartInfo.Arguments = szArgs;
            try
            {
                cmd.Start();

                //Wait if _WaitForCommand is enabled
                if (_WaitForCommand)
                {
                    //if _WaitSecs is 0 or not set (whitch results to 0) wait for application to end infinitely
                    if (_WaitSecs == 0)
                    {
                        cmd.WaitForExit();
                    }
                    //if _WaitSecs is set, wait for application to end bux max _WaitSecs seconds
                    else
                    {
                        cmd.WaitForExit(_WaitSecs * 1000);
                    }
                }
                else
                {
                    //if _WaitSecs is 0 or not set (whitch results to 0) do not wait
                    if (_WaitSecs == 0)
                    {
                       
                    }
                    //if _WaitSecs is set, but _WaitForCommand not, wait _WaitSecs Seconds
                    else
                    {
                        Thread.Sleep(_WaitSecs * 1000);
                    }
                }
            }
            catch (System.ComponentModel.Win32Exception)
            {
                System.Windows.Forms.MessageBox.Show("Command '" + szFilename + "' not found");
            };
        }

        //splits the filename from the arguments
        private String splitFilename(String szCommand)
        {
            int n;

            if (szCommand.ElementAt(0) == '"')
            {
                for (n = 1; n < szCommand.Length; n++)
                {
                    if (szCommand.ElementAt(n) == '"')
                    {
                        return szCommand.Substring(0, n);
                    };
                };
            }
            return szCommand.Split(' ')[0];
        }

        //replaces the regex with the user-given-pass
        private string replaceRegex(String szString, String szPassword, String szRegex)
        {

            for (int i = 0; i < szString.Length; i++)
            {
                if (szString.ElementAt(i) == szRegex.ElementAt(0))
                {

                    for (int c = 0; c < szRegex.Length; c++)
                    {
                        if (szString.ElementAt(i + c) != szRegex.ElementAt(c))
                        {
                            break;
                        }
                        if (c == szRegex.Length - 1)
                        {
                            String szTmp;

                            szTmp = szString.Substring(0, i);
                            szString = szString.Substring(i + c + 1);

                            szTmp = szTmp + szPassword;
                            szString = szTmp + szString;

                            i = i + (szPassword.Length - szRegex.Length);
                        }

                    }
                }
            }
            return szString;
        }

        
    }
}
